/********************************************************************************************************
 * @file	pda_stack.h
 *
 * @brief	This is the header file for BLE SDK
 *
 * @author	BLE GROUP
 * @date	2020.06
 *
 * @par     Copyright (c) 2020, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *          All rights reserved.
 *
 *          Redistribution and use in source and binary forms, with or without
 *          modification, are permitted provided that the following conditions are met:
 *
 *              1. Redistributions of source code must retain the above copyright
 *              notice, this list of conditions and the following disclaimer.
 *
 *              2. Unless for usage inside a TELINK integrated circuit, redistributions
 *              in binary form must reproduce the above copyright notice, this list of
 *              conditions and the following disclaimer in the documentation and/or other
 *              materials provided with the distribution.
 *
 *              3. Neither the name of TELINK, nor the names of its contributors may be
 *              used to endorse or promote products derived from this software without
 *              specific prior written permission.
 *
 *              4. This software, with or without modification, must only be used with a
 *              TELINK integrated circuit. All other usages are subject to written permission
 *              from TELINK and different commercial license may apply.
 *
 *              5. Licensee shall be solely responsible for any claim to the extent arising out of or
 *              relating to such deletion(s), modification(s) or alteration(s).
 *
 *          THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 *          ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *          WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *          DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
 *          DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *          (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *          LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *          ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *          (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *          SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *******************************************************************************************************/

#ifndef STACK_BLE_CONTROLLER_LL_PRDADV_PDA_STACK_H_
#define STACK_BLE_CONTROLLER_LL_PRDADV_PDA_STACK_H_



#include "stack/ble/hci/hci_cmd.h"
#include "stack/ble/controller/ll/ll_stack.h"


/******************************* pda start ***********************************************************************/
_attribute_aligned_(4)
typedef struct {
	u8		pda_phy;	//"le_phy_type_t"
	u8		u8_rsvd[3];


	u16     paEvtCnt;//periodic advertisingpaEventCounter
  	u16		chnIdentifier;		//periodic advertising channel identifier
	u16     bSlot_prdadv_itvl;
	u16     sSlot_prdadv_itvl;
	u16		sSlot_duration_pda;
  	u16		u16_rsvd;

	u32		bSlot_mark_prdadv;

  	u32		paAccessAddr;		//AA shall be set to the Access Address of the periodic advertising
  	u32		paCrcInit;			//Same as the ACL's CRC_Init value
	u32     prdadv_send_cnt; //Periodic ADV sending execution times accumulated

  	ll_mgrChnParam_t chnParam;  //4B aligned

}st_pda_t;
extern st_pda_t *blt_pPda;


int		blt_pda_start_common_1(void);
int		blt_pda_start_common_2(void);
int 	blt_pda_post_common(void);
/******************************* pda end *************************************************************************/







/******************************* prd_adv start *******************************************************************/


typedef struct
{
    u8 		maxNum_perdAdv;
    u8		prd_adv_sel;

}ll_prdadv_mng_t;

extern ll_prdadv_mng_t		bltPrdA;


#define 	PERD_ADV_FIFONUM 						12  // 80/7.5=10.6

#define		PERD_ADV_SLOT_RMV_MSK					BIT(6)
#define		PERD_ADV_SLOT_BUILD_MSK					BIT(7)

_attribute_aligned_(4)
typedef struct ll_prd_adv_para_t{
	u8		prd_adv_en;    //final enable status
	u8		advSet_idx; //remove later
	u8		advHand_mark;  //adv_handle mark
	u8 		unfinish_advData;

	u8		prdadv_index;
	u8		mapping_extadv_idx;
	u8		u8_rsvd1[2];

	u8      big_idx;
	u8		acad_field_len;
	u8      acad_used;
	u8      extAdvSet_idx;

	u8      acad[60]; //33B(no enc bis) or 57B(enc bis), use 60B enough

	u8      property;
	u8		u8_rsvd2;
	u8      with_aux_chain_ind;
	u8      prd_1st_pkt_dataLen;

	u8		chain_ind_num;
	u8		coding_ind;
	u8		txPower_en_len;
	u8		u8_rsvd4;

	u16 	advInter_min;
	u16 	advInter_max;


	u8*		dat_perdAdvData;
	u32     curLen_perdAdvData;
	u32     link_big_handle; //Associated with the big_handle


	u16     rfLen_255_pkt_us;
	u16		n_30us_chain_ind;

	u8 		chain_ind_dataLen[CHAIN_PKT_MAX_NUM];


	u16     prd_evt_us;
	u16		u16_rsvd;

	u16		maxLen_perdAdvData;
	u8		schTsk_wptr;
	u8		schTsk_rptr;

	//Attention: if not 4B aligned, task scheduler will collapse. SO variable must 4B aligned above !!!
	sch_task_t	schTsk_fifo[PERD_ADV_FIFONUM];

	u8		auxPtr_offset;
	u8  	txPower_offset;
	u8		ACAD_advData_offset;
	u8  	rsvd2;


	st_pda_t	pda_tx;


	ll_prd_adv_ind_header_t  prd_adv_1stPkt;  // 16B

}st_prd_adv_t;

typedef int  (*ll_perd_adv_acad_callback_t)(int);
extern ll_perd_adv_acad_callback_t				perd_adv_acad_update_cb;

extern	st_prd_adv_t		*global_pPerdadv;
extern	st_prd_adv_t		*blt_pPerdadv;
extern	st_prd_adv_t		*cur_pPerdadv;

int 			blt_ll_buildPerdAdvSchedulerLinklist(void);
st_prd_adv_t*	blt_ll_search_existing_perdAdv_index_by_advHandle(u8 adv_handle);
u8 				blt_ll_isPerdAdvEnable(u8 adv_handle);
u8 				blt_ll_search_existing_perdAdv_index(u8 advSet_idx);
u8 				blt_ll_search_existing_and_new_perdAdv_index(u8 advSet_idx);

st_prd_adv_t * blt_prdadv_search_existed_and_allocate_new_periodic_adv(u8 advHandle);
st_prd_adv_t * blt_prdadv_search_existed_periodic_adv(u8 advHandle);


void  			blt_prdadv_updatePram(st_prd_adv_t *);
void 			blt_prdadv_task_begin(st_prd_adv_t	*);
void 			blt_prdadv_task_end(st_prd_adv_t	*);

ble_sts_t		blc_hci_le_setPeriodicAdvParam(adv_handle_t adv_handle, u16 advInter_min, u16 advInter_max, perd_adv_prop_t property);
ble_sts_t  		blc_hci_le_setPeriodicAdvData(adv_handle_t adv_handle, data_oper_t operation, u8 advData_len, u8 *advdata);


int 		blt_prd_adv_interrupt_task (int);
int 		blt_prd_adv_mainloop_task (int, void *p);

int			blt_prdadv_start(int slotTask_idx);
int			blt_ll_aux_syncinfo_update(int prdadv_idx);
int 		blt_ll_ctrlPerdAdvChClassUpd(unsigned char *pChm);

void 		blt_reset_prd_adv(void);
/******************************* prd_adv end *********************************************************************/






/******************************* pda_sync start ******************************************************************/

#define 		PDASYNC_TAIL_MARGIN_US							20

_attribute_aligned_(4)
typedef struct {
	u8		pdA_sync_sel;
	u8		pdA_syncing;
	u8		pdA_cacheNum;
	u8		pdA_list_num;

	u8		pdA_synced_num;
	u8		u8_rsvd1[3];


	u32		prdadv_seqnum;
	u32 	tick_pda_sync;
	u32		pdaSync_timeout_us;
}ll_prdadv_sync_t;  //periodic ADV Sync manage

extern ll_prdadv_sync_t		bltPdaSync;


#define			PDA_SYNC_TIMING_ADJUST_EN						1

#if (PDA_SYNC_TIMING_ADJUST_EN)

typedef struct{
	u32 rx_1st_tick;

	s16 sSlot_offset;
	u16 timing_update;
}pda_syncTiming_t;

extern pda_syncTiming_t  pda_sync_timingAdjust[];

#endif



#define			PRDADV_SYNC_FIFONUM								12



#define SYNC_STATE_IDLE					0
#define SYNC_STATE_WAIT_SYNC_INFO		BIT(0)
#define SYNC_STATE_SYNC_INFO_MATCH		BIT(1)
#define SYNC_STATE_SYNCING				BIT(2)
#define SYNC_STATE_SYNCED				BIT(3)


_attribute_aligned_(4)
typedef struct {
	u8		pda_index;
	u8		sync_state;  //when pda_syncing_flg none zero, it may be wait_sync_info, sync_info_matsch or sync_ing
	u8		mapping_auxscan_idx;
	u8		mapping_cache_idx;

	u8		sync_establish;
	u8		sync_lost;
	u8		sync_err_cnt;
	u8		terminate;

	u8		sync_specify;
	u8		sca;
	u8		u8_rsvd1[2];

	u16		pda_interval;  //1.25mS unit
	u16		pda_duration_us;
	u16		tolerance_pda_us;
	u16		sync_early_set_us;
	u16		max_pda_skip;
	u16		max_err_us_per_second;
	u16		pda_pkt_us;
	u16		u16_rsvd;


	s32 	sSlot_mark_prdadv;
//	u32		pda_expect_tick; //no need
	u32		pdaInterval_tick;
  	u32		pda_crcinit;
  	u32		sync_timeout_tick;
  	u32		sync_rx_tick;

	st_pda_t	pda_rx;

	extadv_id_t		pda_id;  	  //8B
//	sync_info_t 	pda_syncInfo;    //18B
//	u8		u8_rsvd2[2];

	//Attention: if not 4B aligned, task scheduler will collapse. SO variable must 4B aligned above !!!
	sch_task_t	schTsk_fifo[PRDADV_SYNC_FIFONUM];


}st_pda_sync_t;  //status of periodic ADV Sync
extern _attribute_aligned_(4)	st_pda_sync_t 		pdAsync_tbl[];
extern _attribute_aligned_(4)	st_pda_sync_t		*blt_pPdAsync;





#define PERDADV_LIST_SIZE						4


_attribute_aligned_(4)
typedef struct {
	extadv_id_t		list_dev_id;  //8B

	u8		synced_mark;
	u8		u8_rsvd[3];
} pda_list_t;
extern	pda_list_t	pdaList_tbl[];



#define PERDADV_CACHE_NUM						4
#define PERDADV_CACHE_MASK						3

#define CACHE_FLAG_IDLE							0
#define CACHE_FLAG_OCCUPIED						1
#define CACHE_FLAG_SYNCING						2
#define CACHE_FLAG_SYNCED						3

_attribute_aligned_(4)
typedef struct {
	u8		cach_index;
	u8		cach_flag;
	u8		prdphy;    //"le_phy_type_t"
	u8		u8_rsvd1[1];

//	u16		u16_rsvd1;

	u32		seq_number;
	u32		header_tick_backup;

	extadv_id_t		pda_dev_id;  //8B
	sync_info_t 	sncInf;    //18B
	u8		u8_rsvd[2];


} pda_cache_t; //periodic ADV cache
extern	pda_cache_t	pdaCache_tbl[];









void 	blt_reset_pda_sync(void);

int 	blt_pda_sync_interrupt_task (int, void*);
int 	blt_pda_sync_mainloop_task (int);

void 	blt_pda_sync_build_task(void);
void 	blt_pda_sync_start(u8);
void 	blt_pda_sync_post(void);
void 	blt_pda_sync_rx(rf_pkt_ext_adv_t*);

int		blt_pda_sync_main_loop(void);
void 	blt_pda_sync_check_timeout(void);
void  	blt_pda_sync_prdadv_data_report(void);

void 	blt_pda_sync_analyze_prdadv_info(st_pda_sync_t *, pda_cache_t *);
bool 	blt_pda_sync_info_process(sync_info_t *);

bool 	blt_isSyncHandleValid (u16 sync_handle);
/******************************* pda_sync end ********************************************************************/





#endif /* STACK_BLE_CONTROLLER_LL_PRDADV_PDA_STACK_H_ */
